package library.net;

import android.app.Application;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.File;

import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
import io.reactivex.Observer;
import library.net.retrofit.ApiFactory;
import library.net.retrofit.RxSchedulers;
import library.net.retrofit.download.DownloadUtils;
import library.net.retrofit.download.IRxProgressListener;
import library.net.retrofit.entity.FileEntity;
import library.net.retrofit.function.RxRetryFunction;
import library.net.retrofit.okhttp.RxOkHttpBuilder;
import library.net.retrofit.response.RxBaseResponse;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * @author Created by qiang.hou on 2018/9/5.
 * @version 1.0
 */
public class RxRetrofitUtils {
    private RxRetrofitUtils() {
    }

    private static class SingleInstanceHolder {
        private static final RxRetrofitUtils INSTANCE = new RxRetrofitUtils();
    }

    public static RxRetrofitUtils getInstance() {
        return SingleInstanceHolder.INSTANCE;
    }

    private Application application;

    /**
     * OkHttpClient
     */
    private OkHttpClient okHttpClient;

    private Converter.Factory converterFactory;
    private CallAdapter.Factory callAdapterFactory;

    /**
     * base url ,default value :null
     */
    private String BASE_URL = null;

    public void init(Application app) {
        application = app;
    }

    public Application getApplication() {
        return application;
    }

    /**
     * init OkHttpClient
     *
     * @param client OkHttpClient
     * @return RxRetrofitBuilder
     */
    public RxRetrofitUtils httpClient(OkHttpClient client) {
        okHttpClient = client;
        return this;
    }

    /**
     * init Converter.Factory
     *
     * @param factory Converter.Factory
     * @return RxRetrofitBuilder
     */
    public RxRetrofitUtils converterFactory(Converter.Factory factory) {
        converterFactory = factory;
        return this;
    }

    /**
     * init CallAdapter.Factory
     *
     * @param factory CallAdapter.Factory
     * @return RxRetrofitBuilder
     */
    public RxRetrofitUtils callAdapterFactory(CallAdapter.Factory factory) {
        callAdapterFactory = factory;
        return this;
    }

    /**
     * init base url
     *
     * @param url base url
     * @return RxRetrofitUtils
     */
    public RxRetrofitUtils baseUrl(String url) {
        BASE_URL = url;
        return this;
    }

    private Retrofit build() {

        if (null == okHttpClient) {
            okHttpClient = new RxOkHttpBuilder().build();
        }

        if (null == converterFactory) {
            // Create a Gson Object
            Gson gson = new GsonBuilder()
                    // config this Gson
                    .setDateFormat("yyyy-MM-dd hh:mm:ss")
                    .create();
            converterFactory = GsonConverterFactory.create(gson);
        }

        if (null == callAdapterFactory) {
            callAdapterFactory = RxJava2CallAdapterFactory.create();
        }

        // 创建Retrofit，baseUrl 中的路径(path)必须以 / 结束
        return new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(converterFactory)
                .addCallAdapterFactory(callAdapterFactory)
                .baseUrl(BASE_URL)
                .build();
    }

    private Retrofit mRetrofit;

    public <T> T create(Class<T> service) {
        if (service == null) {
            throw new RuntimeException("Api service is null!");
        }
        if (null == mRetrofit) {
            mRetrofit = build();
        }
        T t = ApiFactory.getInstance().createApiService(mRetrofit, service);
        if (null != t) {
            return t;
        }
        return mRetrofit.create(service);
    }

    /**
     * 普通网络请求
     *
     * @param observable    from service api
     * @param observer      ui thread observer
     * @param retryFunction retry function
     * @param transformer   thread transformer
     * @param <T>           data
     */
    public <T> void rxCommonCall(
            Observable<RxBaseResponse<T>> observable,
            Observer<T> observer,
            RxRetryFunction retryFunction,
            ObservableTransformer<RxBaseResponse<T>, RxBaseResponse<T>> transformer) {
        if (null != retryFunction) {
            observable = observable.retryWhen(retryFunction);
        }
        observable.compose(transformer).compose(RxSchedulers.<T>response_data()).subscribe(observer);
    }

    /**
     * 下载
     *
     * @param observable       from service api for download （Observable<ResponseBody>）
     * @param entity           description        local file desc
     * @param progressListener progress listener for downloading
     * @param observer         ui thread observer(File)
     */
    public void rxDownloadCall(
            Observable<ResponseBody> observable,
            FileEntity entity,
            final IRxProgressListener progressListener,
            Observer<File> observer) {
        DownloadUtils.download(observable, entity, progressListener, observer);
    }

    /**
     * 下载（适用于后台通过header控制是否支持断点续传的场景）
     *
     * @param call             retrofit2
     * @param entity           description        local file desc
     * @param progressListener progress listener for downloading
     */
    public void rxDownloadCall(
            Call<ResponseBody> call,
            FileEntity entity,
            final IRxProgressListener progressListener) {
        DownloadUtils.download(call, entity, progressListener);
    }
}
